import {
  put, takeLatest, takeEvery, all, select, call, cancel, fork,
} from 'redux-saga/effects'
import { delay } from 'redux-saga'
import { projectLabelView as projectDuck, canvas as canvasDuck } from 'ducks'
import AddLabel from 'graphql/addLabel.graphql'
import UpdateLabel from 'graphql/updateLabel.graphql'
import { gqlMutation } from './utils'

const tasks = {}

function* initItemImage() {
  const windowSize = yield select(canvasDuck.selectors.windowSize)
  if (windowSize !== undefined) {
    const imageInfo = yield select(projectDuck.selectors.imageInfo)
    const scaleWidth = windowSize.w / imageInfo.width
    const scaleHeight = windowSize.h / imageInfo.height
    const scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight
    let mouseWheel
    if (scale >= 1) {
      mouseWheel = scale - 1
    } else {
      mouseWheel = 1 - 1 / scale
    }

    yield put(canvasDuck.creators.actionInitMouseWheel(mouseWheel))
    yield put(
      canvasDuck.creators.actionSetCoordinate({
        x: windowSize.w / 2,
        y: windowSize.h / 2,
      }),
    )
  }
}

function* paintPointSaga(action) {
  const editLabelId = yield select(projectDuck.selectors.editLabelId)
  if (editLabelId === undefined) {
    const selectedBrush = yield select(projectDuck.selectors.activeclassType)
    const tempLabel = yield select(projectDuck.selectors.prePareLabel)
    const tempPoints = tempLabel.points
    switch (selectedBrush) {
      case 'polygon':
        if (tempPoints.length < 3) {
          yield put(projectDuck.creators.actionPrepareLabel(action.x, action.y))
        }
        break
      case 'rectangle':
        if (tempPoints.length < 2) {
          yield put(projectDuck.creators.actionPrepareLabel(action.x, action.y))
        }
        break
      case 'keypoint':
        if (tempPoints.length < 2) {
          yield put(projectDuck.creators.actionPrepareLabel(action.x, action.y))
        }
        break
      default:
        break
    }
  } else {
    yield put(projectDuck.creators.actionLabelAddPoint(action.x, action.y))
  }
}

function* addLabel(points) {
  const itemId = yield select(projectDuck.selectors.activeItemId)
  const classId = yield select(projectDuck.selectors.activeclass)
  const result = yield call(gqlMutation, AddLabel, {
    itemId,
    classId,
    content: { interior: [], exterior: points, tags: [] },
  })
  const newLabel = result.insert_annotation.returning[0]
  const { content, ...others } = newLabel
  yield put(projectDuck.creators.actionReciveNewLable({ ...content, ...others }))
}

function* newPolygon(tempPoints) {
  yield call(addLabel, tempPoints)
}

function* newRectangle(tempPoints) {
  yield call(addLabel, tempPoints)
}

function* newkeyPoink(tempPoints) {
  const activeclassObject = yield select(projectDuck.selectors.activeclassObject)
  console.log(activeclassObject)
  const topLeftX = tempPoints[0][0] < tempPoints[1][0] ? tempPoints[0][0] : tempPoints[1][0]
  const topLeftY = tempPoints[0][1] < tempPoints[1][1] ? tempPoints[0][1] : tempPoints[1][1]
  const width = Math.abs(tempPoints[0][0] - tempPoints[1][0])
  const height = Math.abs(tempPoints[0][1] - tempPoints[1][1])
  const points = Object.keys(activeclassObject.setting.points).reduce((pre, next) => {
    pre.push([topLeftX + width * activeclassObject.setting.points[next].x, topLeftY + height * activeclassObject.setting.points[next].y])
    return pre
  }, [])
  yield call(addLabel, points)
}

function* prepareLabelSaga() {
  const selectedBrush = yield select(projectDuck.selectors.activeclassType)
  const tempLabel = yield select(projectDuck.selectors.prePareLabel)
  const tempPoints = tempLabel.points
  switch (selectedBrush) {
    case 'polygon':
      if (tempPoints.length === 3) {
        yield newPolygon(tempPoints)
      }
      break
    case 'rectangle':
      if (tempPoints.length === 2) {
        yield newRectangle(tempPoints)
      }
      break
    case 'keypoint':
      if (tempPoints.length === 2) {
        yield newkeyPoink(tempPoints)
      }
      break
    default:
      break
  }
}

function* reciveNewLabelSaga(action) {
  yield put(
    projectDuck.creators.actionResetEditAndDo(
      projectDuck.creators.actionSetEditLabelId,
      action.label.id,
    ),
  )
}

function* resetAndDoSaga(action) {
  if (action.action !== undefined) {
    yield put(action.action(...action.args))
  }
}

function* addPointPolygon(action) {
  const isEditPolygonHole = yield select(projectDuck.selectors.isEditPolygonHole)
  const editLabelId = yield select(projectDuck.selectors.editLabelId)
  if (isEditPolygonHole) {
    const holeIndex = yield select(projectDuck.selectors.editHoleIndex)
    yield put(
      projectDuck.creators.actionDoAndUpdate(
        editLabelId,
        projectDuck.creators.actionAddInteriorPoint,
        editLabelId,
        holeIndex,
        action.x,
        action.y,
      ),
    )
  } else {
    yield put(
      projectDuck.creators.actionDoAndUpdate(
        editLabelId,
        projectDuck.creators.actionAddExteriorPoint,
        editLabelId,
        action.x,
        action.y,
      ),
    )
  }
}

function* addPointSaga(action) {
  const selectedBrush = yield select(projectDuck.selectors.activeclassType)
  switch (selectedBrush) {
    case 'polygon':
      yield addPointPolygon(action)
      break
    case 'rectangle':
      break
    case 'keyPoink':
      break
    default:
      break
  }
}

function* newLabelSaga(action) {}

function* updateLabel() {
  const editLabel = yield select(projectDuck.selectors.editLabel)
  const params = {
    id: editLabel.id,
    classId: editLabel.class_id,
    content: { interior: editLabel.interior, exterior: editLabel.exterior, tags: editLabel.tags },
  }
  yield call(delay, 3000)
  yield call(gqlMutation, UpdateLabel, params)
  delete tasks[editLabel.id]
}

function* doAndUpdateSaga(action) {
  yield put(action.action(...action.args))
  const editLabelid = yield select(projectDuck.selectors.editLabelId)
  const fieldTask = tasks[editLabelid]
  if (fieldTask) {
    console.log('cancle task id: ', editLabelid)
    yield cancel(fieldTask) // cancel is no-op if the task has already terminated
  }
  const lastTask = yield fork(updateLabel, action)
  tasks[editLabelid] = lastTask
}

export default function* sagas() {
  yield all([
    takeLatest(canvasDuck.types.INIT_ITEM_IMAGE, initItemImage),
    takeLatest(projectDuck.types.RESET_EDIT_INFO, resetAndDoSaga),
    takeLatest(projectDuck.types.PAINT_POINT, paintPointSaga),
    takeLatest(projectDuck.types.LABEL_ADD_POINT, addPointSaga),
    takeLatest(projectDuck.types.NEW_LABEL, newLabelSaga),
    takeLatest(projectDuck.types.PREPARE_LABEL, prepareLabelSaga),
    takeLatest(projectDuck.types.RECIVE_NEW_LABEL, reciveNewLabelSaga),
    takeEvery(projectDuck.types.DO_AND_UPDATE, doAndUpdateSaga),
  ])
}
